package device

import (
	"container/list"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	MQTT "github.com/eclipse/paho.mqtt.golang"
	"goAdapter/device/commInterface"
	"goAdapter/device/eventBus"
	"goAdapter/httpServer/model"
	"goAdapter/protocol"
	"goAdapter/setting"
	"goAdapter/utils"
	"runtime"
	"sync"
	"time"

	"github.com/robfig/cron"
)

type SlaveEventTemplate struct {
	Type    string `json:"Type"`    //事件类型，online，offline，update
	SlaveID string `json:"SlaveID"` //采集接口名称
}

type DevSlaveTemplate struct {
	DevId               string                               `json:"DevId"`             //采集接口
	DevName             string                               `json:"DevName"`           //设备别名
	CommInterfaceName   string                               `json:"CommInterfaceName"` //通信接口
	CommInterface       commInterface.CommunicationInterface `json:"-"`
	ProInterface        protocol.ProInterface                `json:"-"`
	Protocol            string                               `json:"Protocol"` //通信协议
	Sid                 int                                  `json:"Sid"`      //从机地址
	Enable              bool                                 `json:"Enable"`   //设备状态
	CommInterfaceUpdate chan bool                            `json:"-"`        //通信接口更新
	CommQueueManage     *CommunicationManageTemplate         `json:"-"`        //通信队列
	DevInfo             *DeviceInfoTemplate                  `json:"-"`        //设备信息
	Properties          []DeviceTSLPropertyTemplate          `json:"-"`        //点位列表
	Services            []DeviceTSLServiceTempalte           `json:"-"`        //服务
	SlaveEventBus       eventBus.Bus                         `json:"-"`        //从机事件总线：上线下线
	Cron                *cron.Cron                           `json:"-"`        //定时管理
	ContextCancelFun    context.CancelFunc                   `json:"-"`
	TSLEventSub         eventBus.Sub                         `json:"-"` //点表修改事件
	NodeEventSub        eventBus.Sub                         `json:"-"` //节点设置事件
	LowFreqEventSub     eventBus.Sub                         `json:"-"` //从机低频事件，暂时未用
	ReportClouds        *list.List                           `json:"-"` //需要上报的云列表
}

type DevSlaveMapTemplate struct {
	Lock sync.RWMutex
	Dev  map[string]*DevSlaveTemplate
}

var DevSlaveMap = DevSlaveMapTemplate{
	Lock: sync.RWMutex{},
	Dev:  make(map[string]*DevSlaveTemplate),
}

type InnerMqttTemplate struct {
	Client        MQTT.Client
	DataPushTopic string
}

var InnerMqtt InnerMqttTemplate

func ReportDevStatus() {
	for true {
		time.Sleep(time.Second * 10)
		setting.GetMemState()
		setting.GetDiskState()
		setting.GetRunTime()
		setting.GetCPUInfo()

		aParam := model.ResponseData{
			"0",
			"",
			setting.SystemState,
		}

		sJson, _ := json.Marshal(aParam)
		topic := "/device/event/status"
		InnerMqtt.Client.Publish(topic, 2, false, string(sJson))
	}
}

func InnerMqttInit() error {
	InnerMqtt.DataPushTopic = "/device/event/%s/data"

	// 创建MQTT客户端实例
	options := MQTT.NewClientOptions()
	options.AddBroker("tcp://localhost:1883")
	options.SetClientID("gateway-dev")

	// 连接到MQTT服务器
	InnerMqtt.Client = MQTT.NewClient(options)
	token := InnerMqtt.Client.Connect()
	if token.Wait() && token.Error() != nil {
		return token.Error()
	}

	setting.ZAPS.Debugf("mqtt连接成功")

	//mqtt连接成功后，每隔5s上报一次设备状态
	//go ReportDevStatus()

	return nil
}

func DevSlaveInit() {
	data, err := utils.FileRead("/selfpara/collInterface.json")
	if err != nil {
		setting.ZAPS.Debugf("采集接口配置json文件读取失败 %v", err)
		return
	}
	//定义采集接口参数结构体
	configParamMap := struct {
		CollectInterfaceParam []ConfigParamTemplate
	}{
		CollectInterfaceParam: make([]ConfigParamTemplate, 0),
	}

	err = json.Unmarshal(data, &configParamMap)
	if err != nil {
		setting.ZAPS.Errorf("采集接口配置json文件格式化失败 %v", err)
		return
	}

	for _, v := range configParamMap.CollectInterfaceParam {
		tmp := CreateSlave(&v)
		if tmp == nil {
			setting.ZAPS.Errorf("创建从机[%s]失败", v.DevId)
			return
		}
	}
}

func WriteCollectInterfaceManageToJson() {

	//采集接口配置参数
	type ConfigParamTemplate struct {
		DevId             string   `json:"DevId"`             //采集接口
		CommInterfaceName string   `json:"CommInterfaceName"` //通信接口
		PollPeriod        int      `json:"PollPeriod"`        //采集周期
		OfflinePeriod     int      `json:"OfflinePeriod"`     //离线超时周期
		DeviceNodeCnt     int      `json:"DeviceNodeCnt"`     //设备数量
		DeviceNodeNameMap []string `json:"DeviceNodeNameMap"` //节点名称
		DeviceNodeAddrMap []string `json:"DeviceNodeAddrMap"` //节点地址
		DeviceNodeTypeMap []string `json:"DeviceNodeTypeMap"` //节点类型
	}

	utils.DirIsExist("./selfpara")

	//定义采集接口参数结构体
	configParamMap := struct {
		CollectInterfaceParam []ConfigParamTemplate
	}{
		CollectInterfaceParam: make([]ConfigParamTemplate, 0),
	}

	for _, v := range DevSlaveMap.Dev {
		ParamTemplate := ConfigParamTemplate{
			DevId:             v.DevId,
			CommInterfaceName: v.CommInterfaceName,
			//PollPeriod:        v.PollPeriod,
			//OfflinePeriod:     v.OfflinePeriod,
			//DeviceNodeCnt:     v.DeviceNodeCnt,
		}

		ParamTemplate.DeviceNodeNameMap = make([]string, 0)
		ParamTemplate.DeviceNodeAddrMap = make([]string, 0)
		ParamTemplate.DeviceNodeTypeMap = make([]string, 0)

		//for _, d := range v.DeviceNodeMap {
		//	ParamTemplate.DeviceNodeNameMap = append(ParamTemplate.DeviceNodeNameMap, d.Name)
		//	ParamTemplate.DeviceNodeAddrMap = append(ParamTemplate.DeviceNodeAddrMap, d.Addr)
		//	ParamTemplate.DeviceNodeTypeMap = append(ParamTemplate.DeviceNodeTypeMap, d.Type)
		//}

		configParamMap.CollectInterfaceParam = append(configParamMap.CollectInterfaceParam,
			ParamTemplate)
	}

	sJson, _ := json.Marshal(configParamMap)
	err := utils.FileWrite("/selfpara/collInterface.json", sJson)
	if err != nil {
		setting.ZAPS.Errorf("采集接口配置json文件写入失败 %v", err)
		return
	}
	setting.ZAPS.Debug("采集接口配置json文件写入成功")
}

func WriteSlaveManageToJson() {
	//采集接口配置参数
	type ConfigParamTemplate struct {
		DevId             string `json:"DevId"`             //采集接口
		DevName           string `json:"DevName"`           //采集接口
		CommInterfaceName string `json:"CommInterfaceName"` //通信接口
		Protocol          string `json:"Protocol"`          //通信协议
		Sid               int    `json:"Sid"`               //从机地址
		Enable            bool   `json:"Enable"`            //使能标志
	}

	utils.DirIsExist("./selfpara")

	//定义采集接口参数结构体
	configParamMap := struct {
		CollectInterfaceParam []ConfigParamTemplate
	}{
		CollectInterfaceParam: make([]ConfigParamTemplate, 0),
	}

	for _, v := range DevSlaveMap.Dev {
		ParamTemplate := ConfigParamTemplate{
			DevId:             v.DevId,
			DevName:           v.DevName,
			CommInterfaceName: v.CommInterfaceName,
			Protocol:          v.Protocol,
			Sid:               v.Sid,
			Enable:            v.Enable,
		}

		configParamMap.CollectInterfaceParam = append(configParamMap.CollectInterfaceParam, ParamTemplate)
	}

	sJson, _ := json.Marshal(configParamMap)
	err := utils.FileWrite("/selfpara/collInterface.json", sJson)
	if err != nil {
		setting.ZAPS.Errorf("采集接口配置json文件写入失败 %v", err)
		return
	}
	setting.ZAPS.Debug("采集接口配置json文件写入成功")
}

// 采集接口配置参数
type ConfigParamTemplate struct {
	DevId             string   `json:"DevId"`             //设备唯一ID，后面需要改名字
	DevName           string   `json:"DevName"`           //设备别名
	CommInterfaceName string   `json:"CommInterfaceName"` //通信接口
	Protocol          string   `json:"Protocol"`          //通信协议
	Sid               int      `json:"Sid"`               //从机ID
	Enable            bool     `json:"Enable"`            //设备状态
	PollPeriod        int      `json:"PollPeriod"`        //采集周期
	OfflinePeriod     int      `json:"OfflinePeriod"`     //离线超时周期
	DeviceNodeCnt     int      `json:"DeviceNodeCnt"`     //设备数量
	DeviceNodeNameMap []string `json:"DeviceNodeNameMap"` //节点名称
	DeviceNodeAddrMap []string `json:"DeviceNodeAddrMap"` //节点地址
	DeviceNodeTypeMap []string `json:"DeviceNodeTypeMap"` //节点类型
}

func (d *DevSlaveTemplate) CreateHandleTask() {
	//开启每个设备的命令处理协程
	ctx, cancel := context.WithCancel(context.Background())
	d.ContextCancelFun = cancel

	//创建设备命令处理协程
	go d.CommunicationManageCmd(ctx)
	time.Sleep(1 * time.Microsecond)
	go d.SlaveEventHandle(ctx)
	time.Sleep(1 * time.Microsecond)
	go d.CollectPoll(ctx)
	time.Sleep(1 * time.Microsecond)
	go d.SlaveNodeHandle(ctx)
	if runtime.GOOS == "linux" && runtime.GOARCH == "mipsle" {
		time.Sleep(1 * time.Microsecond)
		go d.SlaveDataPublish(ctx)
	}
}

func CreateSlave(configDev *ConfigParamTemplate) *DevSlaveTemplate {
	//查找通信接口
	index := -1
	for k, v := range commInterface.CommunicationInterfaceMap {
		if v.GetName() == configDev.CommInterfaceName {
			index = k
			break
		}
	}
	if index == -1 {
		return nil
	}

	proInf := protocol.GetProInterface(configDev.Protocol)
	if proInf == nil {
		setting.ZAPS.Errorf("无法找到[%s]协议接口", configDev.Protocol)
		return nil
	}

	proInf.Construct()
	proInf.Init(commInterface.CommunicationInterfaceMap[index])
	proInf.SetSid(configDev.Sid)
	//协议接口连接挪到了设备使能后-CollectPoll
	//if !proInf.Connect() {
	//	setting.ZAPS.Warnf("proInf[%s] connect err", proInf.GetName())
	//}
	setting.ZAPS.Debugf("找到[%s]协议接口", proInf.GetName())

	salveName := configDev.DevId

	slave := &DevSlaveTemplate{
		DevId:               salveName,
		DevName:             configDev.DevName,
		CommInterfaceName:   configDev.CommInterfaceName,
		CommInterface:       commInterface.CommunicationInterfaceMap[index],
		ProInterface:        proInf,
		Protocol:            configDev.Protocol,
		Sid:                 configDev.Sid,
		Enable:              configDev.Enable,
		CommInterfaceUpdate: make(chan bool),
		CommQueueManage:     NewCommunicationManageTemplate(),
		SlaveEventBus:       eventBus.NewBus(),
		Cron:                cron.New(),
		TSLEventSub:         eventBus.NewSub(),
		NodeEventSub:        eventBus.NewSub(),
		LowFreqEventSub:     eventBus.NewSub(),
		ReportClouds:        list.New(),
	}

	setting.ZAPS.Debugf("[%s]设备绑定[%s]协议", salveName, proInf.GetName())
	setting.ZAPS.Debugf("[%s]协议从机ID=%d", proInf.GetName(), proInf.GetSid())
	setting.ZAPS.Debugf("[%s]协议绑定通信接口[%s]", proInf.GetName(), proInf.GetComInf().GetName())

	//订阅点表修改和删除事件
	slave.SlaveEventBus.Subscribe("/nodeTable/state", slave.TSLEventSub)
	slave.SlaveEventBus.Subscribe("/node/set", slave.NodeEventSub)
	slave.SlaveEventBus.Subscribe("/cloud/report/switch", slave.LowFreqEventSub)

	//初始化设备信息
	node := &DeviceInfoTemplate{
		LastCommRTC:    "1970-01-01 00:00:00",
		CommTotalCnt:   0,
		CommSuccessCnt: 0,
		CurCommFailCnt: 0,
		CommStatus:     "offLine",
		DevState:       "正重启服务",
	}

	slave.DevInfo = node

	//初始化点表
	//tmp.NewPointMap()
	slave.Properties = slave.NewVariables()
	slave.Services = slave.NewServices()

	//记录从机设备
	DevSlaveMap.Dev[slave.DevId] = slave

	////打开通信接口
	//if slave.ProInterface.GetUseComIf() {
	//	slave.CommInterface.Open()
	//}

	slave.CreateHandleTask()

	return slave
}

/*
*******************************************************
功能描述：	增加接口
参数说明：
返回说明：
调用方式：
全局变量：
读写时间：
注意事项：
日期    ：
*******************************************************
*/
func NewCollectInterface(salveName, commInterfaceName string,
	pollPeriod, offlinePeriod int, deviceNodeCnt int) *DevSlaveTemplate {

	//index := -1
	//for k, v := range commInterface.CommunicationInterfaceMap {
	//	if v.GetName() == commInterfaceName {
	//		index = k
	//		break
	//	}
	//}
	//if index == -1 {
	//	return nil
	//}
	//
	//slave := &DevSlaveTemplate{
	//	DevId:               salveName,
	//	CommInterfaceName:   commInterfaceName,
	//	CommInterface:       commInterface.CommunicationInterfaceMap[index],
	//	CommInterfaceUpdate: make(chan bool),
	//	CommQueueManage:     NewCommunicationManageTemplate(),
	//	//PollPeriod:          pollPeriod,
	//	//OfflinePeriod:       offlinePeriod,
	//	//DeviceNodeCnt:       deviceNodeCnt,
	//	//DeviceNodeMap:       make(map[string]*DeviceInfoTemplate),
	//	SlaveEventBus:   eventBus.NewBus(),
	//	Cron:           cron.New(),
	//	TSLLuaStateMap: make(map[string]*lua.LState),
	//	TSLEventSub:    eventBus.NewSub(),
	//}
	//
	////将lua文件加载到虚拟机中,每个采集接口单独一组，多个采集接口就不会冲突
	//for _, v := range DeviceTSLMap {
	//	//订阅物模型的修改和删除事件
	//	v.Event.Subscribe("modify", slave.TSLEventSub)
	//	v.Event.Subscribe("delete", slave.TSLEventSub)
	//
	//	setting.ZAPS.Infof("采集接口[%s]打开物模型[%s]", salveName, v.Name)
	//	err, lState := v.DeviceTSLOpenPlugin()
	//	if err != nil {
	//		setting.ZAPS.Infof("采集接口[%s]打开物模型[%s]失败", salveName, v.Name)
	//		continue
	//	}
	//	slave.TSLLuaStateMap[v.Name] = lState
	//}
	//
	//ctx, cancel := context.WithCancel(context.Background())
	//slave.ContextCancelFun = cancel
	//
	////打开通信接口
	//slave.CommInterface.Open()
	//
	////str := fmt.Sprintf("@every %dm%ds", slave.PollPeriod/60, slave.PollPeriod%60)
	////setting.ZAPS.Infof("采集接口[%s]定时轮询任务开启 %dm%ds执行一次", salveName, slave.PollPeriod/60, slave.PollPeriod%60)
	//////添加定时任务
	////_ = slave.Cron.AddFunc(str, slave.CommunicationManagePoll)
	////slave.Cron.Start()
	//////创建通信接口接收协程
	////if slave.CommInterface.GetType() != commInterface.CommTypeIoIn {
	////	go slave.CommQueueManage.CommunicationManageProcessReceiveData(ctx, slave.CommInterface)
	////}
	//////创建通信队列处理协程
	////go slave.CommunicationManageDel(ctx)
	//////创建通信接口更新协程
	////go slave.CommInterfaceProcessUpdate(ctx)
	//////创建物模型更新协程
	////go slave.SlaveEventHandle(ctx)
	//
	////创建设备命令处理协程
	//go slave.CommunicationManageCmd(ctx)
	//
	//return slave
	return nil
}

func DeleteSlave(slaveName string) error {

	DevSlaveMap.Lock.Lock()
	slave, ok := DevSlaveMap.Dev[slaveName]
	DevSlaveMap.Lock.Unlock()
	if !ok {
		setting.ZAPS.Errorf("delete slave err, dev not exist")
		return errors.New("从机设备不存在")
	}

	slave.Cron.Stop()

	//相关协程退出
	slave.ContextCancelFun()

	//删除从机
	delete(DevSlaveMap.Dev, slaveName)

	//删除从机对应的点表
	index := -1
	for k := 0; k < len(DeviceTSLMap); k++ {
		if DeviceTSLMap[k].Name == slaveName {
			index = k
			break
		}
	}

	if index == -1 {
		setting.ZAPS.Warnw("找不到[%s]从机对应的点表", slaveName)
	} else {
		DeviceTSLMap = append(DeviceTSLMap[:index], DeviceTSLMap[index+1:]...)
		WriteDeviceTSLParamToJson()
	}

	WriteSlaveManageToJson()

	return nil
}

func AddSlave(config *ConfigParamTemplate) error {

	DevSlaveMap.Lock.Lock()
	_, ok := DevSlaveMap.Dev[config.DevId]
	DevSlaveMap.Lock.Unlock()
	if ok {
		return errors.New("slaveName is exist")
	}

	//增加从机
	tmp := CreateSlave(config)
	if tmp == nil {
		return errors.New("添加从机失败")
	}

	//写入点表
	WriteSlaveManageToJson()

	return nil
}

func AddCollectInterface(slaveName string, commName string, PollPeriod, OfflinePeriod int) error {

	DevSlaveMap.Lock.Lock()
	_, ok := DevSlaveMap.Dev[slaveName]
	DevSlaveMap.Lock.Unlock()
	if ok {
		return errors.New("slaveName is exist")
	}

	DevSlaveMap.Dev[slaveName] = NewCollectInterface(slaveName, commName, PollPeriod, OfflinePeriod, 0)
	WriteCollectInterfaceManageToJson()

	return nil
}

func ModifySlaveBack(config *ConfigParamTemplate) error {
	slave, ok := DevSlaveMap.Dev[config.DevId]
	if !ok {
		return errors.New("从机不存在")
	}

	index := -1
	for k, v := range commInterface.CommunicationInterfaceMap {
		if v.GetName() == config.CommInterfaceName {
			index = k
			break
		}
	}
	if index == -1 {
		return errors.New("通信接口不存在")
	}

	proInf := protocol.GetProInterface(config.Protocol)
	if proInf == nil {
		return errors.New("通信协议不存在")
	}

	//不管什么参数发生变化，都重新建立所有的逻辑，停止以前的采集动作
	slave.ContextCancelFun()

	//关闭旧的通信接口
	slave.CommInterface.Close()

	proInf.Construct()
	proInf.Init(commInterface.CommunicationInterfaceMap[index])
	proInf.SetSid(config.Sid)
	if !proInf.Connect() {
		setting.ZAPS.Warnf("proInf connect err")
	}

	//重新赋值相关变量
	slave.DevName = config.DevName
	slave.CommInterfaceName = config.CommInterfaceName
	slave.CommInterface = commInterface.CommunicationInterfaceMap[index]
	slave.ProInterface = proInf
	slave.Protocol = config.Protocol
	slave.Sid = config.Sid

	////打开通信接口
	//if slave.ProInterface.GetUseComIf() {
	//	slave.CommInterface.Open()
	//}

	slave.CreateHandleTask()

	//写入点表
	WriteSlaveManageToJson()

	return nil
}

func ModifySlave(config *ConfigParamTemplate) error {
	slave, ok := DevSlaveMap.Dev[config.DevId]
	if !ok {
		return errors.New("从机不存在")
	}

	index := -1
	for k, v := range commInterface.CommunicationInterfaceMap {
		if v.GetName() == config.CommInterfaceName {
			index = k
			break
		}
	}
	if index == -1 {
		return errors.New("通信接口不存在")
	}

	//不管什么参数发生变化，都重新建立所有的逻辑，停止以前的采集动作
	slave.ContextCancelFun()

	//关闭旧的通信接口
	slave.CommInterface.Close()

	proInf := slave.ProInterface
	proInf.Construct()
	proInf.Init(commInterface.CommunicationInterfaceMap[index])
	proInf.SetSid(config.Sid)
	if !proInf.Connect() {
		setting.ZAPS.Warnf("proInf connect err")
	}

	//重新赋值相关变量
	slave.DevName = config.DevName
	slave.CommInterfaceName = config.CommInterfaceName
	slave.CommInterface = commInterface.CommunicationInterfaceMap[index]
	slave.Sid = config.Sid

	////打开通信接口
	//if slave.ProInterface.GetUseComIf() {
	//	slave.CommInterface.Open()
	//}

	slave.CreateHandleTask()

	//写入点表
	WriteSlaveManageToJson()

	return nil
}

func EnableSlave(devId string, enable bool) error {
	slave, ok := DevSlaveMap.Dev[devId]
	if !ok {
		return errors.New("从机不存在")
	}

	if slave.Enable != enable {
		slave.Enable = enable

		setting.ZAPS.Infof("将会修改从机[%s]状态为", slave.DevId)

		//写入点表
		WriteSlaveManageToJson()
	}

	return nil
}

func ModifyCollectInterface(slaveName string, commName string, pollPeriod, offlinePeriod int) error {

	slave, ok := DevSlaveMap.Dev[slaveName]
	if !ok {
		return errors.New("采集接口不存在")
	}

	////轮询周期发生了变化
	//if slave.PollPeriod != pollPeriod {
	//	//停止
	//	slave.Cron.Stop()
	//	//重启
	//	slave.Cron = cron.New()
	//	str := fmt.Sprintf("@every %dm%ds", pollPeriod/60, pollPeriod%60)
	//	setting.ZAPS.Infof("采集任务[%s] %+v", slave.DevId, str)
	//	//添加定时任务
	//	_ = slave.Cron.AddFunc(str, slave.CommunicationManagePoll)
	//	slave.Cron.Start()
	//}

	//通信接口发生了变化
	if slave.CommInterfaceName != commName {
		//关闭旧的通信接口
		slave.CommInterface.Close()

		//相关协程退出
		slave.ContextCancelFun()

		index := -1
		for k, v := range commInterface.CommunicationInterfaceMap {
			if v.GetName() == commName {
				index = k
				break
			}
		}
		if index == -1 {
			return nil
		}
		slave.CommInterface = commInterface.CommunicationInterfaceMap[index]
		ctx, cancel := context.WithCancel(context.Background())
		slave.ContextCancelFun = cancel

		//打开通信接口
		slave.CommInterface.Open()

		//创建通信接口接收协程
		go slave.CommQueueManage.CommunicationManageProcessReceiveData(ctx, slave.CommInterface)
		//创建通信队列处理协程
		go slave.CommunicationManageDel(ctx)
		//创建通信接口更新协程
		go slave.CommInterfaceProcessUpdate(ctx)
		//创建物模型更新协程
		go slave.SlaveEventHandle(ctx)
	}

	slave.CommInterfaceName = commName
	//slave.PollPeriod = pollPeriod
	//slave.OfflinePeriod = offlinePeriod
	WriteCollectInterfaceManageToJson()

	return nil
}

/*
*******************************************************
功能描述：	删除接口
参数说明：
返回说明：
调用方式：
全局变量：
读写时间：
注意事项：
日期    ：
*******************************************************
*/
func DeleteCollectInterface(slaveName string) error {

	DevSlaveMap.Lock.Lock()
	slave, ok := DevSlaveMap.Dev[slaveName]
	DevSlaveMap.Lock.Unlock()
	if !ok {
		return errors.New("采集接口不存在")
	}

	//if len(slave.DeviceNodeMap) > 0 {
	//	return errors.New("采集接口已添加设备，请先删除设备")
	//}
	slave.Cron.Stop()

	//相关协程退出
	slave.ContextCancelFun()

	delete(DevSlaveMap.Dev, slaveName)

	WriteCollectInterfaceManageToJson()

	return nil
}

// NewPointMap jy add 增加点表映射
func (d *DevSlaveTemplate) NewPointMap() {

	//node := &DeviceInfoTemplate{
	//	//Index:          len(d.DeviceNodeMap),
	//	//Name:           dName,
	//	//Addr:           dAddr,
	//	//Type:           dType,
	//	LastCommRTC:    "1970-01-01 00:00:00",
	//	CommTotalCnt:   0,
	//	CommSuccessCnt: 0,
	//	CurCommFailCnt: 0,
	//	CommStatus:     "offLine",
	//}

	//这个函数完全可以去掉，逻辑放外面
	properties := d.NewVariables()
	d.Properties = append(d.Properties, properties...)
	services := d.NewServices()
	d.Services = append(d.Services, services...)

	//d.DevInfo = node
}

func (d *DevSlaveTemplate) NewVariables() []DeviceTSLPropertyTemplate {

	properties := make([]DeviceTSLPropertyTemplate, 0)

	for _, v := range DeviceTSLMap {
		if v.Name == d.DevId {
			properties = append(properties, v.Properties...)
		}
	}

	return properties
}

func (d *DevSlaveTemplate) NewServices() []DeviceTSLServiceTempalte {

	services := make([]DeviceTSLServiceTempalte, 0)

	for _, v := range DeviceTSLMap {
		if v.Name == d.DevId {
			services = append(services, v.Services...)
		}
	}

	return services
}

/*
func (d *DevSlaveTemplate) NewDeviceNode(dName string, dType string, dAddr string) {

	node := &DeviceInfoTemplate{
		Index:          len(d.DeviceNodeMap),
		Name:           dName,
		Addr:           dAddr,
		Type:           dType,
		LastCommRTC:    "1970-01-01 00:00:00",
		CommTotalCnt:   0,
		CommSuccessCnt: 0,
		CurCommFailCnt: 0,
		CommStatus:     "offLine",
	}

	properties := node.NewVariables()
	node.Properties = append(node.Properties, properties...)
	services := node.NewServices()
	node.Services = append(node.Services, services...)

	d.DeviceNodeMap[dName] = node
}
*/

func (d *DevSlaveTemplate) AddDeviceNode(dName string, dType string, dAddr string) (bool, string) {

	//node := &DeviceInfoTemplate{}
	//node.Index = len(d.DeviceNodeMap)
	//node.Name = dName
	//node.Addr = dAddr
	//node.Type = dType
	//node.LastCommRTC = "1970-01-01 00:00:00"
	//node.CommTotalCnt = 0
	//node.CommSuccessCnt = 0
	//node.CurCommFailCnt = 0
	//node.CommStatus = "offLine"
	////node.VariableMap = make([]VariableTemplate, 0)
	////variables := node.NewVariables()
	////node.VariableMap = append(node.VariableMap, variables...)
	//
	//properties := node.NewVariables()
	//node.Properties = append(node.Properties, properties...)
	//services := node.NewServices()
	//node.Services = append(node.Services, services...)

	//d.DeviceNodeMap[dName] = node

	//d.DeviceNodeCnt++

	return true, "add success"
}

func (d *DevSlaveTemplate) DeleteDeviceNode(dName string) {

	//_, ok := d.DeviceNodeMap[dName]
	//if ok {
	//	d.DeviceNodeCnt--
	//	delete(d.DeviceNodeMap, dName)
	//}
}

func (d *DevSlaveTemplate) GetDeviceNode(dAddr string) *DeviceInfoTemplate {

	//for _, v := range d.DeviceNodeMap {
	//	if v.Addr == dAddr {
	//		return v
	//	}
	//}

	return nil
}

func (d *DevSlaveTemplate) CommInterfaceProcessUpdate(ctx context.Context) {
	setting.ZAPS.Debugf("采集接口[%s]处理更新协程3/4进入", d.DevId)
	for {
		select {
		case <-ctx.Done():
			setting.ZAPS.Debugf("采集接口[%s]处理更新协程3/4退出", d.DevId)
			return
		case <-d.CommInterfaceUpdate:
			{
				setting.ZAPS.Debugf("通信接口[%s]发生更新事件", d.CommInterfaceName)
				//旧采集队列接收数据协程退出
				d.CommQueueManage.QuitChan <- true
				rt := d.CommInterface.Open()
				if rt != true {
					setting.ZAPS.Debugf("通信接口[%s]重新打开失败", d.CommInterfaceName)
				} else {
					setting.ZAPS.Debugf("通信接口[%s]重新打开成功", d.CommInterfaceName)
				}
				time.Sleep(100 * time.Millisecond)
				//创建新通信接口接收协程
				setting.ZAPS.Debugf("采集接口[%s]处理更新协程重新打开", d.DevId)
				if d.CommInterface.GetType() != commInterface.CommTypeIoIn {
					go d.CommQueueManage.CommunicationManageProcessReceiveData(ctx, d.CommInterface)
				}
			}
		}
	}
}

func (d *DevSlaveTemplate) SlaveEventHandle(ctx context.Context) {
	setting.ZAPS.Debugf("从机设备[%s]点表更新协程2/3进入", d.DevId)
	for {
		select {
		case <-ctx.Done():
			time.Sleep(1 * time.Millisecond) //保证其它协程先退出
			setting.ZAPS.Debugf("从机设备[%s]点表更新协程2/3退出", d.DevId)
			return
		case msg := <-d.TSLEventSub.Out():
			{
				setting.ZAPS.Debugf("recv TSLEventSub msg %v", msg)
				eventMsg := msg.(DeviceTSLEventTemplate)
				if eventMsg.Type == "modify" {
					d.ContextCancelFun()

					//更新点表
					d.Properties = d.NewVariables()
					d.CreateHandleTask()
				}
			}
		case msg := <-d.NodeEventSub.Out():
			{
				setting.ZAPS.Debugf("recv NodeEventSub msg %v", msg)
				eventMsg := msg.(*NodeEventTemplate)
				if eventMsg.Type == "set" {
					cmd := NodeCmdTemplate{}
					var i int
					for i = 0; i < len(d.Properties); i++ {
						if d.Properties[i].ID == eventMsg.NodeId {
							cmd.node = &d.Properties[i]
							cmd.node.Value.SetVal = eventMsg.Val
							cmd.FunType = FunTypeSet
							setting.ZAPS.Debugf("设置设备[%s]节点[%s]值[%s]", d.DevId, cmd.node.ID, cmd.node.Value.SetVal)
							d.CommQueueManage.CommunicationManageAddCmd(cmd)
							break
						}
					}

					if i >= len(d.Properties) {
						setting.ZAPS.Warnf("找不到节点[%s]", eventMsg.NodeId)
					}
				}
			}
		case msg := <-d.LowFreqEventSub.Out():
			{
				setting.ZAPS.Debugf("recv NodeEventSub msg %v", msg)
			}
		default:
			{
				time.Sleep(1 * time.Second)
			}
		}
	}
}

func (d *DevSlaveTemplate) CommunicationManageDel(ctx context.Context) {
	setting.ZAPS.Debugf("采集接口[%s]命令对列监听协程2/4进入", d.DevId)
	//for {
	//	select {
	//	case <-ctx.Done():
	//		setting.ZAPS.Debugf("采集接口[%s]命令对列监听协程2/4退出", d.DevId)
	//		return
	//	case cmd := <-d.CommQueueManage.EmergencyRequestChan:
	//		{
	//			setting.ZAPS.Infof("采集接口[%s]处理紧急任务 节点名称[%v] 命令函数名词[%v]", d.DevId, cmd.DeviceName, cmd.FunName)
	//			node, ok := d.DeviceNodeMap[cmd.DeviceName]
	//			if !ok {
	//				continue
	//			}
	//			rxResult := CommunicationRxTemplate{}
	//			if d.CommInterface.GetType() == commInterface.CommTypeIoIn {
	//				rxResult = d.CommQueueManage.CommunicationStateMachineIoIn(cmd,
	//					d.DevId,
	//					d.CommInterface,
	//					node,
	//					&d.SlaveEventBus,
	//					d.TSLLuaStateMap,
	//					d.OfflinePeriod)
	//			} else {
	//				rxResult = d.CommQueueManage.CommunicationStateMachine(cmd,
	//					d.DevId,
	//					d.CommInterface,
	//					node,
	//					&d.SlaveEventBus,
	//					d.TSLLuaStateMap,
	//					d.OfflinePeriod)
	//			}
	//			//更新设备在线数量
	//			d.DeviceNodeOnlineCnt = 0
	//			for _, v := range d.DeviceNodeMap {
	//				if v.CommStatus == "onLine" {
	//					d.DeviceNodeOnlineCnt++
	//				}
	//			}
	//
	//			setting.ZAPS.Debugf("采集接口[%s]处理紧急任务完成，处理结果%v", d.DevId, rxResult)
	//			d.CommQueueManage.EmergencyAckChan <- rxResult
	//		}
	//	default:
	//		{
	//			select {
	//			case req := <-d.CommQueueManage.DirectDataRequestChan:
	//				{
	//					ack := d.CommQueueManage.CommunicationDirectDataStateMachine(req, d.CommInterface)
	//					d.CommQueueManage.DirectDataAckChan <- ack
	//				}
	//			case cmd := <-d.CommQueueManage.CommonRequestChan:
	//				{
	//					node, ok := d.DeviceNodeMap[cmd.DeviceName]
	//					if !ok {
	//						continue
	//					}
	//
	//					setting.ZAPS.Debugf("采集接口[%s]通信队列剩余节点数%d", d.DevId, len(d.CommQueueManage.CommonRequestChan))
	//					if d.CommInterface.GetType() == commInterface.CommTypeIoIn {
	//						d.CommQueueManage.CommunicationStateMachineIoIn(cmd,
	//							d.DevId,
	//							d.CommInterface,
	//							node,
	//							&d.SlaveEventBus,
	//							d.TSLLuaStateMap,
	//							d.OfflinePeriod)
	//					} else {
	//						d.CommQueueManage.CommunicationStateMachine(cmd,
	//							d.DevId,
	//							d.CommInterface,
	//							node,
	//							&d.SlaveEventBus,
	//							d.TSLLuaStateMap,
	//							d.OfflinePeriod)
	//					}
	//					//更新设备在线数量,当本次采集最后一个设备时进行更新
	//					if len(d.CommQueueManage.CommonRequestChan) == 0 {
	//						d.DeviceNodeOnlineCnt = 0
	//						for _, v := range d.DeviceNodeMap {
	//							if v.CommStatus == "onLine" {
	//								d.DeviceNodeOnlineCnt++
	//							}
	//						}
	//					}
	//				}
	//			default:
	//				time.Sleep(100 * time.Millisecond)
	//			}
	//		}
	//	}
	//}
}

func (d *DevSlaveTemplate) CommunicationManageCmd(ctx context.Context) {
	setting.ZAPS.Debugf("从机设备[%s]命令处理协程1/3进入", d.DevId)
	for {
		select {
		case <-ctx.Done():
			setting.ZAPS.Debugf("从机设备[%s]命令处理协程1/3退出", d.DevId)
			return
		case cmd := <-d.CommQueueManage.CmdRequestChan:
			{
				d.DevInfo.CommTotalCnt++
				nodeTmp := protocol.NodeProperty{
					ID:         cmd.node.ID,
					RegType:    cmd.node.RegType,
					RegAddr:    cmd.node.RegAddr,
					AccessMode: cmd.node.AccessMode,
					DataType:   cmd.node.DataType,
					Value:      cmd.node.Value.Value, //这句完成设置后也去掉
					SetValue:   cmd.node.Value.SetVal,
				}

				var ret int

				if cmd.FunType == FunTypeGet {
					ret = d.ProInterface.GetNode(&nodeTmp)
					if ret == 0 {
						cmd.node.Value.Value = nodeTmp.Value
						cmd.node.Value.TimeStamp = time.Now().Format("2006-01-02 15:04:05")
						setting.ZAPS.Debugf("get node name = %s, val = %v",
							cmd.node.ID, cmd.node.Value.Value)
					} else {
						setting.ZAPS.Errorf("get node[%s] err", cmd.node.ID)
					}
				}
				if cmd.FunType == FunTypeSet {
					if nodeTmp.AccessMode == protocol.NodeAccessReadOnly {
						setting.ZAPS.Warnf("set node [%s] mode is readonly", cmd.node.ID)
						break
					}
					ret = d.ProInterface.SetNode(&nodeTmp)
					if ret == 0 {
						setting.ZAPS.Infof("set node name = %s, val = %v",
							cmd.node.ID, cmd.node.Value.SetVal)
					} else {
						setting.ZAPS.Errorf("set node[%s] err", cmd.node.ID)
					}
				}

				if ret == 0 {
					d.DevInfo.CommSuccessCnt++
					d.DevInfo.LastCommRTC = time.Now().Format("2006-01-02 15:04:05")

					if d.DevInfo.CommStatus == "offLine" {
						d.DevInfo.CommStatus = "onLine"
						d.DevInfo.DevState = "正常"
						//发送事件信息
						content := SlaveEventTemplate{
							Type:    "onLine",
							SlaveID: d.DevId,
						}
						err := d.SlaveEventBus.Publish("/slave/state", content)
						setting.ZAPS.Debugf("从机[%s]发布上线消息", d.DevName)
						if err != nil {
							setting.ZAPS.Errorf("从机[%s]发布上线消息失败", d.DevName)
						}
					}
				} else {
					//网关启动后默认是“正重启服务”状态，如果一开始就连不上从机，那么切换状态为离线
					d.DevInfo.DevState = "设备离线"

					if d.DevInfo.CommStatus == "onLine" {
						d.DevInfo.CommStatus = "offLine"

						//发送事件信息
						content := SlaveEventTemplate{
							Type:    "offLine",
							SlaveID: d.DevId,
						}
						err := d.SlaveEventBus.Publish("/slave/state", content)
						setting.ZAPS.Debugf("从机[%s]发布离线消息", d.DevName)
						if err != nil {
							setting.ZAPS.Errorf("从机[%s]发布离线消息失败", d.DevName)
						}
					}
					d.DevInfo.CurCommFailCnt++
				}
			}
		default:
			time.Sleep(100 * time.Millisecond)
		}
	}
}

func (d *DevSlaveTemplate) CommunicationManagePoll() {

	//cmd := CommunicationCmdTemplate{}
	//for _, v := range d.DeviceNodeMap {
	//	cmd.DevId = d.DevId
	//	cmd.DeviceName = v.Name
	//	cmd.FunName = "GetDeviceRealVariables"
	//	d.CommQueueManage.CommunicationManageAddCommon(cmd)
	//}
	setting.ZAPS.Debugf("采集接口[%s]通信对列节点总数为%d", d.DevId, len(d.CommQueueManage.CommonRequestChan))
}

func (d *DevSlaveTemplate) CollectPoll(ctx context.Context) {
	setting.ZAPS.Debugf("从机设备[%s]采集协程3/3进入", d.DevId)
	for {
		select {
		case <-ctx.Done():
			setting.ZAPS.Debugf("从机设备[%s]采集协程3/3退出", d.DevId)
			return
		default:
			{
				//如果没有使能，那么不进行采集
				if !d.Enable {
					//setting.ZAPS.Debugf("从机[%s]未使能", d.DevId)
					time.Sleep(2 * time.Second)
					continue
				}

				//如果使能从机，并且协议接口未连接/打开，那么先连接或者打开通信接口
				if !d.ProInterface.IsConnect() {
					d.ProInterface.Connect()
				}

				if len(d.Properties) == 0 {
					d.DevInfo.DevState = "点表空"
					time.Sleep(1 * time.Second)
					continue
				}

				cmd := NodeCmdTemplate{}
				for i := 0; i < len(d.Properties); i++ {
					cmd.node = &d.Properties[i]
					cmd.FunType = FunTypeGet
					setting.ZAPS.Debugf("采集设备[%s]节点[%s]", d.DevId, cmd.node.ID)
					d.CommQueueManage.CommunicationManageAddCmd(cmd)
					time.Sleep(1 * time.Millisecond)
				}
			}
		}
	}
	//cmd := NodeCmdTemplate{}
	//for true {
	//	for i := 0; i < len(d.Properties); i++ {
	//		cmd.node = &d.Properties[i]
	//		cmd.FunType = FunTypeGet
	//		setting.ZAPS.Debugf("采集设备[%s]节点[%s]", d.DevId, cmd.node.ID)
	//		d.CommQueueManage.CommunicationManageAddCmd(cmd)
	//		time.Sleep(3 * time.Second)
	//	}
	//}
}

func (d *DevSlaveTemplate) ReportHandler(node *DeviceTSLPropertyTemplate) {
	//对设备绑定的每个云进行上报
	e := d.ReportClouds.Front()
	for e != nil {
		cloudName := e.Value.(string)
		cloud, ok := CloudMap.Cloud[cloudName]
		if !ok {
			setting.ZAPS.Errorf("在CloudMap中找不到云[%s]", cloudName)
			e = e.Next()
			continue
		}
		setting.ZAPS.Debugf("采集设备[%s]节点[%s]将会上报到云[%s]", d.DevId, node.ID, cloudName)

		//在线那么就上报，不在线就离线存储
		if cloud.IsOnline {
			//云处理上报的时候需要获得设备信息
			node.Pdev = d
			CloudMap.ReportEventBus.Publish(cloud.ReportTopic, node)
		} else {
			setting.ZAPS.Warnf("云[%s]不在线，将会触发离线存储", cloudName)
		}
		e = e.Next()
	}
}

func (d *DevSlaveTemplate) SlaveNodeHandle(ctx context.Context) {
	setting.ZAPS.Debugf("从机设备[%s]点位处理协程4/4进入", d.DevId)
	//先把所有点位置初值
	for i := 0; i < len(d.Properties); i++ {
		d.Properties[i].Value.LastReportTime = time.Now().Unix()
		//先暂时把所有的上报周期先设置为5
		d.Properties[i].Params.ReportPeriod = 10
	}

	for {
		select {
		case <-ctx.Done():
			setting.ZAPS.Debugf("从机设备[%s]点位处理协程4/4退出", d.DevId)
			return
		default:
			{
				//如果没有使能，那么不进行处理
				if !d.Enable {
					time.Sleep(2 * time.Second)
					continue
				}

				//如果点表为空，那么不进行处理
				if len(d.Properties) == 0 {
					time.Sleep(1 * time.Second)
					continue
				}

				//如果云初始化还未完成，那么不进行处理
				if !CloudMap.IsReady {
					time.Sleep(1 * time.Second)
					continue
				}

				time.Sleep(2 * time.Second) //再等等云的上线操作
				setting.ZAPS.Debugf("从机设备[%s]上报轮询操作开始...", d.DevId)

				for i := 0; i < len(d.Properties); i++ {
					if d.Properties[i].ReportMode == "变化上报" {
						if d.Properties[i].Value.Value != d.Properties[i].Value.OldValue {
							setting.ZAPS.Debugf("采集设备[%s]节点[%s]将会上报", d.DevId, d.Properties[i].ID)
							d.ReportHandler(&d.Properties[i])
							d.Properties[i].Value.OldValue = d.Properties[i].Value.Value
						}
					}
					if d.Properties[i].ReportMode == "周期上报" {
						currTime := time.Now().Unix()
						if currTime-d.Properties[i].Value.LastReportTime >= d.Properties[i].Params.ReportPeriod {
							setting.ZAPS.Debugf("采集设备[%s]节点[%s]将会上报", d.DevId, d.Properties[i].ID)
							d.ReportHandler(&d.Properties[i])
							d.Properties[i].Value.LastReportTime = currTime
						}
					}
					time.Sleep(100 * time.Millisecond)
				}
			}
		}
	}
}

func (d *DevSlaveTemplate) SlaveDataPublish(ctx context.Context) {
	//10s后进入数据推送模式
	time.Sleep(10 * time.Second)
	setting.ZAPS.Debugf("从机设备[%s]数据推送协程5/5入", d.DevId)
	for {
		select {
		case <-ctx.Done():
			setting.ZAPS.Debugf("从机设备[%s]数据推送协程5/5退出", d.DevId)
			return
		default:
			{
				//如果没有使能，那么不进行推送
				if !d.Enable {
					time.Sleep(2 * time.Second)
					continue
				}

				if len(d.Properties) == 0 {
					d.DevInfo.DevState = "点表空"
					time.Sleep(1 * time.Second)
					continue
				}

				type DeviceDataTemplate struct {
					ID         string `json:"ID"`
					Name       string `json:"Name"`
					AccessMode int    `json:"AccessMode"`
					DataType   string `json:"DataType"`
					Value      string `json:"Value"`
					TimeStamp  string `json:"TimeStamp"`
				}

				aParam := struct {
					Code    string               `json:"Code"`
					Message string               `json:"Message"`
					Data    []DeviceDataTemplate `json:"Data"`
				}{
					Code:    "0",
					Message: "",
					Data:    make([]DeviceDataTemplate, 0),
				}

				for _, v := range d.Properties {
					DataMap := DeviceDataTemplate{
						ID:         v.ID,
						Name:       v.Name,
						AccessMode: v.AccessMode,
						DataType:   v.DataType,
						Value:      fmt.Sprintf("%v", v.Value.Value),
						TimeStamp:  v.Value.TimeStamp,
					}
					aParam.Data = append(aParam.Data, DataMap)
				}
				sJson, _ := json.Marshal(aParam)

				topic := fmt.Sprintf(InnerMqtt.DataPushTopic, d.DevId)
				//setting.ZAPS.Debugf("topic = %s", topic)

				InnerMqtt.Client.Publish(topic, 2, false, string(sJson))
				time.Sleep(2 * time.Second)
			}
		}
	}
}

func (d *DevSlaveTemplate) ReportCloudAdd(cloudName string) {
	d.ReportClouds.PushBack(cloudName)
}

func (d *DevSlaveTemplate) ReportCloudRemove(cloudName string) {
	e := d.ReportClouds.Front()
	for e != nil {
		if e.Value == cloudName {
			d.ReportClouds.Remove(e)
			break
		}
		e = e.Next()
	}
}
